home *** CD-ROM | disk | FTP | other *** search
/ Nebula 1 / Nebula One.iso / Educational / PrimeThreads / Source / PrimeThreadsApp.m < prev   
Text File  |  1995-06-12  |  5KB  |  142 lines

  1. /*********************/
  2. /* PrimeThreadsApp.m */
  3. /*********************/
  4. #import "PrimeThreadsApp.h"
  5. #import <appkit/Button.h>
  6. #import <appkit/Control.h>
  7. #import <appkit/chunk.h>
  8. #import <dpsclient/dpsNeXT.h>
  9. #import <math.h>
  10.  
  11. /* the code is much smaller when you take out the comments ;-) */
  12.  
  13. /*
  14.  * thePrimeList is maintained by the NXChunk system.  GROW_BY
  15.  * is how much the structure's malloc'ed space will grow, when
  16.  * it needs to be expanded.  The chunk is also initialized
  17.  * with GROW_BY bytes.
  18.  */  
  19. #define GROW_BY 8192
  20. /* every UPDATE_PERIOD seconds, a timed entry calls updateFieldsGlue */
  21. #define UPDATE_PERIOD 0.25
  22.  
  23. struct primeList {
  24. /* see /usr/include/appkit/chunk.h for a description of the NXChunk */
  25.     NXChunk chunk;
  26. /* number of primes in the list */
  27.     int numPrimes;
  28. /* This is just a bogus declaration. There can be any number of primes. */
  29.     int thePrimes[2];
  30. } *thePrimeList;
  31.  
  32. /* this mutex guards thePrimeList */
  33. mutex_t primeListLock;
  34.  
  35. /* this is the function the timed entry calls */
  36. void updateFieldsGlue(DPSTimedEntry te, double now, void *self)
  37. /* we, in turn, call the updateFields method (we're just glue) */
  38. { [(id)self updateFields]; }
  39.  
  40. /* findPrimes is executed on its own thread.  it never stops. */
  41. void findPrimes(int ignored)
  42. {
  43.     int counter, possiblePrime = 5, testLimit;
  44.     BOOL isPrime;
  45.  
  46.     while (YES) /* repeat forever */
  47.     {
  48. /* isPrime starts at YES.  if an exact divisor is found, it becomes NO */
  49.         isPrime = YES;
  50. /* for any non-prime integer x, one of its factors is less than sqrt(x) */
  51.         testLimit = sqrt(possiblePrime);
  52.         for (counter=1; isPrime && (thePrimeList->thePrimes[counter]<=testLimit); counter++)
  53.             if (possiblePrime % thePrimeList->thePrimes[counter] == 0)
  54.                 isPrime = NO;
  55.         if (isPrime)
  56.         {
  57. /* lock the mutex before changing the list */
  58.           mutex_lock(primeListLock);
  59. /* another prime for the list! */
  60.           thePrimeList->numPrimes++;
  61. /*
  62.  * grow the chunk.  usually this does nothing; sometimes more
  63.  * space gets allocated.
  64.  */
  65.           thePrimeList =
  66.             (struct primeList *)NXChunkGrow((NXChunk *)thePrimeList,
  67.               thePrimeList->numPrimes * sizeof(int));
  68. /* place our newly-certified prime into the list. */
  69.           thePrimeList->thePrimes[thePrimeList->numPrimes - 1] = possiblePrime;
  70. /* unlock the mutex now that we're done with the list */
  71.           mutex_unlock(primeListLock);
  72.         }
  73.         possiblePrime += 2; /* don't bother with even numbers */
  74. /* tell the scheduler that this is a convenient time to run other threads */
  75.         cthread_yield();
  76.     }
  77. }
  78.  
  79. @implementation PrimeThreadsApp
  80.  
  81. /* IB outlets */
  82. - setNumPrimesField:anObject
  83. { numPrimesField = anObject; return self; }
  84. - setHighestPrimeField:anObject
  85. { highestPrimeField = anObject; return self; }
  86.  
  87. - appDidInit:sender
  88. {
  89.    /* allocate the mutex */
  90.     primeListLock = mutex_alloc();
  91.    /*
  92.     * initialize thePrimeList with GROW_BY bytes of memory
  93.     * to start with, and make it grow by GROW_BY bytes when
  94.     * it expands.
  95.     */
  96.     thePrimeList = (struct primeList *)NXChunkMalloc(GROW_BY, GROW_BY);
  97.    /* we start the list with 2 primes: 2 and 3. */
  98.     thePrimeList->numPrimes = 2;
  99.     thePrimeList->thePrimes[0] = 2;
  100.     thePrimeList->thePrimes[1] = 3;
  101.    /*
  102.     * start up the primeFinderThread. It will never stop, but we can
  103.     * suspend and resume the thread, which is just as good.
  104.     */
  105.     primeFinderThread = cthread_fork(findPrimes, 0);
  106.    /* since we will never want to join the thread, we detach it. */
  107.     cthread_detach(primeFinderThread);
  108.    /* create the timed entry that will handle updating the fields */
  109.     DPSAddTimedEntry(UPDATE_PERIOD, updateFieldsGlue,
  110.       (void *)self, NX_BASETHRESHOLD);
  111.     return self;
  112. }
  113.  
  114. - toggleGoStop:sender
  115. {
  116. /*
  117.  * cthread_thread gets us the actual thread, which is a part of
  118.  * the cthread structure.  struct cthread has a lot of other neat
  119.  * stuff in it, too, but we don't (explicitly) use any of it.
  120.  * thread_resume() and thread_suspend() just want the thread identifier,
  121.  * not a cthread, and we give it to 'em.
  122.  */
  123.     if ([sender state] == YES) /* turn it on */
  124.         thread_resume(cthread_thread(primeFinderThread));
  125.     else /* turn it off */
  126.         thread_suspend(cthread_thread(primeFinderThread));
  127.     return self;
  128. }
  129.  
  130. - updateFields
  131. {
  132. /* lock the mutex before reading the list */
  133.     mutex_lock(primeListLock);
  134.     [numPrimesField setIntValue:thePrimeList->numPrimes];
  135.     [highestPrimeField setIntValue:thePrimeList->thePrimes[thePrimeList->numPrimes - 1]];
  136. /* unlock the mutex, now that we're done with the list */
  137.     mutex_unlock(primeListLock);
  138.     return self;
  139. }
  140.  
  141. @end
  142.